-
Notifications
You must be signed in to change notification settings - Fork 114
[example] Add example for Swift Service Lifecycle #522
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
…-lambda-runtime into sebsto/servicelifecycle
2432ed3
to
018d9ce
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR adds a comprehensive example demonstrating Swift Service Lifecycle integration with AWS Lambda and PostgreSQL RDS, along with minor fixes to Docker command references and local server implementation.
- Adds a complete ServiceLifecycle+Postgres example with AWS infrastructure setup
- Fixes Docker command references in format checking scripts
- Updates local server implementation to handle return values properly
Reviewed Changes
Copilot reviewed 18 out of 18 changed files in this pull request and generated 3 comments.
Show a summary per file
File | Description |
---|---|
scripts/check-format-linux.sh | Fixed Docker command references from 'container' to 'docker' |
Sources/AWSLambdaRuntime/Lambda+LocalServer.swift | Updated return type handling and error management in local server |
Examples/Streaming/samconfig.toml | Added SAM configuration for streaming example |
Examples/ServiceLifecycle+Postgres/* | Complete new example with PostgreSQL integration, infrastructure templates, and documentation |
.licenseignore | Added .toml files to license ignore list |
.github/workflows/pull_request.yml | Added new example to CI workflow |
@@ -106,7 +106,7 @@ internal struct LambdaHTTPServer { | |||
eventLoopGroup: MultiThreadedEventLoopGroup = .singleton, | |||
logger: Logger, | |||
_ closure: sending @escaping () async throws -> Result | |||
) async throws -> Result { | |||
) async throws -> Swift.Result<Result, any Error> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The return type change from Result
to Swift.Result<Result, any Error>
appears to be a breaking change that could affect API consumers. This should be carefully considered for backward compatibility.
) async throws -> Swift.Result<Result, any Error> { | |
) async throws -> Result { |
Copilot uses AI. Check for mistakes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So when does this function throw an error and when does it return the error as a Result?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Out of interest what was causing the shutdown error, that you are ignoring now
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So when does this function throw an error and when does it return the error as a Result?
when the user types CTRL-C to stop the server and the server is part of a service lifecycle group
Out of interest what was causing the shutdown error, that you are ignoring now
The reported error is Channel I/O
by an attempt to read/write on a closed channel.
I don't know the root cause.
Because this happens on the local server, just used for testing, and at the time of shutdown. I think it's sfe to ignore the error and let the app terminate.
@adam-fowler This is a new example. The rest is "just" a PostgreSQL + service lifecycle example. I provide a SAM template to setup the database in a secure way (private network, restrictive security groups, password stored in secret manager) |
// TODO: ideally, I want to do this once, after serviceGroup.run() is done | ||
// but before the handler is called | ||
logger.trace("Checking database") | ||
try await prepareDatabase() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For Hummingbird I created a wrapper service for a service which called a closure before running the wrapped service. This allowed me to have prelude code like your prepareDatabase
. You could use this to wrap the lambda runtime and run the prepareDatabase beforehand
/// Wrap another service to run after a prelude closure has completed
struct PreludeService<S: Service>: Service, CustomStringConvertible {
let prelude: @Sendable () async throws -> Void
let service: S
var description: String {
"PreludeService<\(S.self)>"
}
init(service: S, prelude: @escaping @Sendable () async throws -> Void) {
self.service = service
self.prelude = prelude
}
func run() async throws {
try await self.prelude()
try await self.service.run()
}
}
extension Service {
/// Build existential ``PreludeService`` from an existential `Service`
func withPrelude(_ prelude: @escaping @Sendable () async throws -> Void) -> Service {
PreludeService(service: self, prelude: prelude)
}
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using the PostgresNIO driver, can we run a prelude code (that will send SQL commands on the connection) before service.run()
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just tried it and the answer is "yes" :-)
@@ -106,7 +106,7 @@ internal struct LambdaHTTPServer { | |||
eventLoopGroup: MultiThreadedEventLoopGroup = .singleton, | |||
logger: Logger, | |||
_ closure: sending @escaping () async throws -> Result | |||
) async throws -> Result { | |||
) async throws -> Swift.Result<Result, any Error> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So when does this function throw an error and when does it return the error as a Result?
@@ -106,7 +106,7 @@ internal struct LambdaHTTPServer { | |||
eventLoopGroup: MultiThreadedEventLoopGroup = .singleton, | |||
logger: Logger, | |||
_ closure: sending @escaping () async throws -> Result | |||
) async throws -> Result { | |||
) async throws -> Swift.Result<Result, any Error> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Out of interest what was causing the shutdown error, that you are ignoring now
@adam-fowler Thank you for the initial review. I added |
Now that task cancellation works, re publishing this PR with a new example for Swift Service Lifecycle